﻿using System;
using System.Collections.Generic;
using System.Linq;

namespace Mbs.Messaging.Imp
{
    [Serializable]
    public partial class Subscriber<TMessage> : MarshalByRefObject, ISubscriber<TMessage>
    {
        private readonly ICollection<ObserverHandler<TMessage>> observers;
        private readonly ICollection<PreFilterHandler<TMessage>> preFilters;
        private readonly ICollection<FilterHandler<TMessage>> filters;

        private readonly Type Type = typeof(TMessage);

        public Subscriber():this(
            new List<ObserverHandler<TMessage>>()
            , new List<PreFilterHandler<TMessage>>()
            , new List<FilterHandler<TMessage>>())
        
        {
        }

        public Subscriber(ICollection<ObserverHandler<TMessage>> observers
            , ICollection<PreFilterHandler<TMessage>> preFilters
            , ICollection<FilterHandler<TMessage>> filters)
        {
            if (observers == null)
                throw new ArgumentNullException("observers");
            if (preFilters == null)
                throw new ArgumentNullException("preFilters");
            if (filters == null)
                throw new ArgumentNullException("filters");

            this.observers = observers;
            this.preFilters = preFilters;
            this.filters = filters;
        }

        public string Name { get; set; }
        public IMessageListnerManager ListnerManager { get; set; }

        public IDisposable Subscribe(ObserverHandler<TMessage> handler)
        {
            if (handler == null
               || observers.Contains(handler))
                return DisposeAction.Empty;

            var observer = handler.Target;

            ListnerManager.OnObserverAdding(observer, Name, Type);
            observers.Add(handler);
            ListnerManager.OnObserverAdded(observer, Name, Type);

            return new DisposeAction(() => Unsubscribe(handler));
        }
 
        public void Unsubscribe(ObserverHandler<TMessage> handler)
        {
            if (handler == null
                || !observers.Contains(handler))
                return;

            ListnerManager.OnObserverRemoving(handler.Target, Name, Type);
            observers.Remove(handler);
            ListnerManager.OnObserverRemoved(handler.Target, Name, Type);
        }

        public IDisposable SubscribePreFilter(PreFilterHandler<TMessage> handler)
        {
            if (handler == null
                || preFilters.Contains(handler))
                return DisposeAction.Empty;

            ListnerManager.OnPreFilterAdding(handler.Target, Name, Type);
            preFilters.Add(handler);
            ListnerManager.OnPreFilterAdded(handler.Target, Name, Type);
            return new DisposeAction(()=>UnsubscribePreFilter(handler));
        }

        public void UnsubscribePreFilter(PreFilterHandler<TMessage> handler)
        {
            if (handler == null
                || !preFilters.Contains(handler))
                return;

            ListnerManager.OnPreFilterRemoving(handler.Target, Name, Type);
            preFilters.Remove(handler);
            ListnerManager.OnPreFilterRemoved(handler.Target, Name, Type);
        }

        public IDisposable SubscribeFilter(FilterHandler<TMessage> handler)
        {
            if (handler == null
                || filters.Contains(handler))
                return DisposeAction.Empty;

            ListnerManager.OnFilterAdding(handler.Target, Name, Type);
            filters.Add(handler);
            ListnerManager.OnFilterAdded(handler.Target, Name, Type);

            return new DisposeAction(()=>UnsubscribeFilter(handler));
        }

        public void UnsubscribeFilter(FilterHandler<TMessage> handler)
        {
            if (handler == null
                || !filters.Contains(handler))
                return;

            ListnerManager.OnFilterRemoving(handler.Target, Name, Type);
            filters.Remove(handler);
            ListnerManager.OnFilterRemoved(handler.Target, Name, Type);
        }


        ObserverHandler<TMessage>[] ISubscriber<TMessage>.Observers
        {
            get
            {
                return observers.ToArray();
            }
        }

        public PreFilterHandler<TMessage>[] PreFilters
        {
            get
            {
                return preFilters.ToArray();
            }
        }

        public FilterHandler<TMessage>[] Filters
        {
            get
            {
                return filters.ToArray();
            }
        }

        public void ClearObservers()
        {
            var items = observers.ToArray();
            if (items != null && items.Length > 0)
                for (int i = 0; i < items.Length; i++)
                    items[i] = null;

            observers.Clear();     
        }

        public void ClearPreFilters()
        {
            var items = preFilters.ToArray();
            if (items != null && items.Length > 0)
                for (int i = 0; i < items.Length; i++)
                    items[i] = null;

            preFilters.Clear();   
        }

        public void ClearFilters()
        {
            var items = filters.ToArray();
            if (items != null && items.Length > 0)
                for (int i = 0; i < items.Length; i++)
                    items[i] = null;

            filters.Clear();   
        }

        public void ClearAll()
        {
            ClearObservers();
            ClearFilters();
            ClearPreFilters();
        }

        public override object InitializeLifetimeService()
        {
            return null;
        }
    }
}
